package org.cybzacg.convert.converters.essential;


import lombok.extern.slf4j.Slf4j;
import org.cybzacg.convert.annotation.Converter;
import org.cybzacg.convert.context.ConversionContext;
import org.cybzacg.convert.core.AbstractTypeConverter;
import org.cybzacg.convert.enums.ConversionPriority;
import org.cybzacg.convert.enums.ConversionType;
import org.cybzacg.convert.exception.ConversionException;

/**
 * 字符类型转换器
 * 专门处理字符类型的转换
 *
 * @author cybzacg.blog
 * @version 3.0
 * @since 3.0
 */
@Slf4j
@Converter(
    name = "CharacterConverter",
    priority = ConversionPriority.ESSENTIAL,
    description = "字符类型转换器，处理各种类型到字符值的转换",
    enabled = true,
    version = "3.0",
    author = "cybzacg.blog",
    supportedTypes = {Character.class, char.class},
    tags = {"character", "char", "basic", "conversion"}
)
public class CharacterConverter extends AbstractTypeConverter {

    public CharacterConverter() {
        super(ConversionPriority.ESSENTIAL);
        log.debug("CharacterConverter 初始化完成，优先级: {}", ConversionPriority.ESSENTIAL);
    }

    @Override
    protected ConversionType getConversionType() {
        return ConversionType.CHARACTER;
    }

    @Override
    @SuppressWarnings("unchecked")
    protected <T> T doConvert(Object source, Class<T> targetType, T defaultValue, ConversionContext context)
            throws Exception {

        log.debug("开始字符类型转换: 源类型={}, 目标类型={}, 默认值={}",
                 source != null ? source.getClass().getSimpleName() : "null",
                 targetType.getSimpleName(),
                 defaultValue);

        if (source == null) {
            log.debug("源对象为null，返回默认值: {}", defaultValue);
            return defaultValue;
        }

        // 如果已经是字符类型，直接返回
        if (source instanceof Character) {
            log.debug("源对象已经是字符类型，直接返回: {}", source);
            return (T) source;
        }

        // 如果是基本类型char
        if (source.getClass() == char.class) {
            Character result = (char) source;
            log.debug("基本类型char转换: {} -> {}", source, result);
            return (T) result;
        }

        // 转换为字符值
        Character result = convertToCharacter(source, context);
        log.debug("字符类型转换完成: {} -> {}", source, result);

        return (T) result;
    }

    /**
     * 将对象转换为字符值
     *
     * @param source 源对象
     * @param context 转换上下文
     * @return 字符值
     * @throws ConversionException 转换失败时抛出
     */
    protected Character convertToCharacter(Object source, ConversionContext context) throws ConversionException {
        log.debug("开始将对象转换为字符值: 源类型={}", source != null ? source.getClass().getSimpleName() : "null");

        if (source == null) {
            log.debug("源对象为null，返回默认字符'\\0'");
            return '\0';
        }

        Character result;

        // 字符串转换
        if (source instanceof String) {
            result = convertStringToCharacter((String) source);
            log.debug("字符串转换结果: '{}' -> {}", source, result);
            return result;
        }

        // 数值转换
        if (source instanceof Number number) {
            result = convertNumberToCharacter(number);
            log.debug("数值转换结果: {} -> {}", source, result);
            return result;
        }

        // 布尔值转换
        if (source instanceof Boolean) {
            result = convertBooleanToCharacter((Boolean) source);
            log.debug("布尔值转换结果: {} -> {}", source, result);
            return result;
        }

        // 其他类型，尝试通过字符串转换
        result = convertObjectToCharacter(source);
        log.debug("对象转换结果: {} -> {}", source.getClass().getSimpleName(), result);
        return result;
    }

    /**
     * 转换字符串为字符
     *
     * @param str 字符串
     * @return 字符
     * @throws ConversionException 转换失败时抛出
     */
    protected Character convertStringToCharacter(String str) throws ConversionException {
        if (str == null || str.isEmpty()) {
            return '\0';
        }

        // 如果字符串长度为1，直接返回第一个字符
        if (str.length() == 1) {
            return str.charAt(0);
        }

        // 如果字符串长度大于1，尝试解析为数字
        try {
            int codePoint = Integer.parseInt(str.trim());
            if (codePoint >= Character.MIN_VALUE && codePoint <= Character.MAX_VALUE) {
                return (char) codePoint;
            } else {
                throw new ConversionException("字符串 '" + str + "' 转换为字符失败：数值超出字符范围");
            }
        } catch (NumberFormatException e) {
            // 不是数字，返回第一个字符
            log.debug("字符串长度大于1且不是数字格式，返回第一个字符: '{}' -> {}", str, str.charAt(0));
            return str.charAt(0);
        }
    }

    /**
     * 转换数值为字符
     *
     * @param number 数值
     * @return 字符
     * @throws ConversionException 转换失败时抛出
     */
    protected Character convertNumberToCharacter(Number number) throws ConversionException {
        if (number == null) {
            return '\0';
        }

        int codePoint = number.intValue();

        // 检查是否在字符范围内
        if (codePoint >= Character.MIN_VALUE && codePoint <= Character.MAX_VALUE) {
            return (char) codePoint;
        } else {
            throw new ConversionException("数值 " + number + " 转换为字符失败：数值超出字符范围");
        }
    }

    /**
     * 转换布尔值为字符
     *
     * @param bool 布尔值
     * @return 字符
     */
    protected Character convertBooleanToCharacter(Boolean bool) {
        if (bool == null) {
            return '\0';
        }

        return bool ? '1' : '0';
    }

    /**
     * 转换对象为字符
     *
     * @param obj 对象
     * @return 字符
     */
    protected Character convertObjectToCharacter(Object obj) {
        if (obj == null) {
            return '\0';
        }

        // 尝试通过toString()方法转换
        String str = obj.toString();
        try {
            return convertStringToCharacter(str);
        } catch (ConversionException e) {
            log.debug("对象转换为字符失败，返回默认字符'\\0': {}", e.getMessage());
            return '\0';
        }
    }

    @Override
    public boolean supports(Class<?> targetType) {
        return targetType == Character.class || targetType == char.class;
    }

    @Override
    public Class<?> getSupportedType() {
        return Character.class;
    }

    /**
     * 检查字符是否为数字
     *
     * @param ch 字符
     * @return 是否为数字
     */
    public static boolean isDigit(Character ch) {
        return ch != null && Character.isDigit(ch);
    }

    /**
     * 检查字符是否为字母
     *
     * @param ch 字符
     * @return 是否为字母
     */
    public static boolean isLetter(Character ch) {
        return ch != null && Character.isLetter(ch);
    }

    /**
     * 检查字符是否为空白字符
     *
     * @param ch 字符
     * @return 是否为空白字符
     */
    public static boolean isWhitespace(Character ch) {
        return ch != null && Character.isWhitespace(ch);
    }

    /**
     * 转换为大写字符
     *
     * @param ch 字符
     * @return 大写字符
     */
    public static Character toUpperCase(Character ch) {
        return ch != null ? Character.toUpperCase(ch) : null;
    }

    /**
     * 转换为小写字符
     *
     * @param ch 字符
     * @return 小写字符
     */
    public static Character toLowerCase(Character ch) {
        return ch != null ? Character.toLowerCase(ch) : null;
    }
}
